This document explains some of the compile and link errors you might see due to misuse of Exception and RTTI macros.
Misuse of Exception Macros
Consider the following code:
class X
{
public:
FW_DECLARE_AUTO(X)
public:
X();
~X();
};
FW_DEFINE_AUTO(X)
X::X()
{
FW_END_CONSTRUCTOR
}
X::~X()
{
FW_START_DESTRUCTOR
}
void foo()
{
X x1;
}
The above code correctly uses the four required macros to make class X be an AutoDestruct class. In the examples that follow, we show the compile or link errors that appear if we "forget" or misuse one or more of the macros. The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
The FW_DECLARE_AUTO declares some functions that are defined by the FW_DEFINE_AUTO macro. If the FW_DECLARE_AUTO macro is omitted, the compiler will emit errors when the FW_DEFINE_AUTO macro is compiled.
2) Omit the FW_DEFINE_AUTO macro
Link Error : undefined ‘X::operator delete(void*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Link Error : undefined ‘FW_PrivGetDestroyProc(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
Link Error : undefined ‘FW_PrivGetAutoName(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
This is the reverse of case 1). Here, we assume the FW_DECLARE_AUTO macro is present, but the FW_DEFINE_AUTO macro is missing. In this case, some functions are declared, but never defined, so the error isn't detected until link time.
3) Omit both the FW_DECLARE_AUTO and FW_DEFINE_AUTO macros
Link Error : undefined ‘FW_PrivGetDestroyProc<1X>(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
Link Error : undefined ‘FW_PrivGetAutoName<1X>(constX*)’ (code)
Referenced from ‘X::~X()’ in Part.cpp
Referenced from ‘X::X()’ in Part.cpp
If you forget both the FW_DECLARE_AUTO and the FW_DEFINE_AUTO macros for a class, but then use the FW_END_CONSTRUCTOR and/or FW_START_DESTRUCTOR, you will get link errors like the above. These errors are not detected until compile time because the two functions shown are declared as template functions, but the implementations for the templates are created only through the FW_DEFINE_AUTO macro.
4) Private FW_DECLARE_AUTO
This is a more subtle problem. Suppose you declared your class like this:
class X
{
FW_DECLARE_AUTO(X)
public:
X();
~X();
};
Since members of classes are private by default, the member functions defined by the FW_DECLARE_AUTO macro above will be private. This will result in errors like the following:
Error : illegal access to protected/private member
Suppose that the function foo() above allocated an instance of class X using new, like this:
void foo()
{
X* x1 = new X;
}
Dynamically allocated AutoDestruct objects must be allocated with FW_NEW. If you forget and use regular operator new instead, you'll get a compile time error:
Error : illegal access to protected/private member
Part.cpp line 130 X* x2 = new X();
This error happens because the FW_DECLARE_AUTO macro declares the standard operator new to be private.
6) Use FW_NEW on a non-AutoDestruct object
Once you get in the habit of using FW_NEW, it's easy to make the mistake of using FW_NEW on a non-AutoDestruct object. For example, assume class Y is not an AutoDestruct object, and you write something like this:
void foo()
{
Y* y = FW_NEW(Y, ());
}
You should then seen a compile error like this:
Error : function call '__nw(unsigned long, FW_CPrivWatcher)' does not match
'__nw(unsigned long)'
'__nw(unsigned long, void *)'
Part.cpp line 135 (Y*) ( new(FW_CPrivWatcher(FW_PrivGetDeleteProc((const Y*)0))) Y(), FW_PrivWatcher_Pop() )
This is because FW_NEW uses a overloaded variant of operator new that is only defined by the FW_DECLARE_AUTO macro.
7) Use FW_DEFINE_AUTO twice for the same class
Sometimes it's convient to create a new class by copying code from another class and then renaming. If you do this by hand and forget to rename the class in the FW_DEFINE_AUTO macro, you'll be invoking the FW_DEFINE_AUTO macro twice for the same class. This will show up as a compile time error if both instances of the macro are in the same .cpp file, or as a link-time error if they are in separate .cpp files.
8) Use FW_DEFINE_AUTO where a FW_DECLARE_AUTO should be used
Suppose you use the FW_DEFINE_AUTO macro in the class declaration by mistake. This will cause a whole series of errors, beginning with these:
The above code correctly uses the FW_DECLARE_CLASS and FW_DEFINE_CLASS_Mn macros required to make classes have runtime type identification. In the examples that follow, we show the compile or link errors that appear if we "forget" or misuse one or more of the macros. The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
1) Omit FW_DECLARE_CLASS
Suppose we left out the FW_DECLARE_CLASS macro for class A. We'd then get these compile-time errors:
Error : 'gAncestors' is not a struct/union/class member
Error : 'PrivVirtualGetClassInfo' is not a struct/union/class member
Part.cpp line 1
FW_DECLARE_CLASS macro declares some static data members and a virtual function. If you forget the FW_DECLARE_CLASS macro but use the FW_DEFINE_CLASS_Mn macro, the compiler emit errors for the references to undeclared data and functions.
2) Omit FW_DEFINE_CLASS_Mn
Suppose we left out the FW_DEFINE_CLASS_M0 macro for class A. We'd then get the following link-time errors:
Link Error : undefined ‘A::gClassInfo’ (data)
Referenced from ‘FW_PrivStaticGetClassInfo<1A>(A*)’ in Part.cpp
Referenced from ‘B::gAncestors’ in Part.cpp
Link Error : missing vtable ‘A::__vt’
Check that all virtual functions and static members are defined
In this case, the members are declared but never defined (implemented), so the error doesn't show up until link time. Note in particular the last link error. Many C++ compilers generated the vtable for a class in the translation unit that implements the first virtual function declared for the class. Since by convention, we normally place the FW_DECLARE_CLASS macro at the top of the class declaration, the virtual function declared by the FW_DECLARE_CLASS macro is the first virtual function. Since it isn't implemented, the compiler doesn't generate the vtable; hence the error "missing vtable ‘A::__vt’".